package com.youpingou.service.impl;

import com.youpingou.dao.SkuRepository;
import com.youpingou.service.SkuSearchService;
import com.youpingou.vo.SearchResult;
import com.youpingou.vo.SearchSku;
import com.youpingou.vo.SkuResult;
import com.youpingou.vo.SkuSearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

@Service
public class SkuSearchServiceImpl implements SkuSearchService {

    @Autowired
    private SkuRepository skuRepository;

    /**
     * 搜索的核心业务就在此方法中完成
     * @param req
     * @return SearchResult是BaseResult的子类
     * elasticsearch中的搜索方法有：
     * 1 自定义方法 findByxxx格式
     * 2 自定义查询：termQuery、booleanQuery、MatchQuery、rangeQuery、fuzzyQuery
     * 此处我们应该选择哪种方式？
     * 选择第2种方式，为什么选择第2种方式？
     * 因为此处的条件查询，条件太多了，用findBy..........难度太大
     *
     * 本方法主要实现根据3级分类进行多条件搜索（暂时先不做关键字搜索）
     *
     *  由于是多条件查询，多条件查询，一定要使用BooleanQuery
     *  商品搜索查询条件是叠加的，所以此处应该使用连接词must
     */
    public SearchResult search(SkuSearchRequest req){
        //1 创建条件查询构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //2 创建BooleanQuery，添加条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //3 添加多条件：根据u3级分类id查找
        //int 如何比较,使用TermQuery比较
        boolQueryBuilder.must(QueryBuilders.termQuery("cat3_id",req.getCatid()));

        //4. 条件二：验证brand_id
        if(req.getBrand_id()!=null&&!"".equals(req.getBrand_id())){
            boolQueryBuilder.must(QueryBuilders.termQuery("brand_id",req.getBrand_id()));
        }

        //5. 条件三：规格搜索
        //5.1 将规格转成Map集合
        HashMap<String,String> map = null;
        // 判断spec_list是否有值
        if(req.getSpec_list()!=null&&!"".equals(req.getSpec_list())){
            map = new HashMap<>();
            //1. 分割字符  机身颜色=金色     内存=4GB      机身颜色=
            String[] spec_list_array = req.getSpec_list().split(",");
            //2. 遍历数组
            for (String s:spec_list_array){
                //3. 根据等号切割字符串
                String[] values = s.split("=");
                //4. values[0] 机身颜色    内存
                //   values[1]    金色     4GB
                if(values.length==1){
                    //5. 当机身颜色没有对应的数据的时候，表明页面选择的是“不限”，此处就可以删除
                    map.remove(values[0]);
                }else{
                    map.put(values[0],values[1]);
                }
            }
        }

        //5.2 添加过滤规格的条件

        if(map!=null){
            //1. 遍历map集合
            // 遍历Map集合方式一
            // Set<Map.Entry<String, String>> entries = map.entrySet();
            // for(Map.Entry<String, String> entry:entries){
            //   String key = entry.getKey();
            //   String value = entry.getValue();
            // }

            // 遍历Map集合方式二
            Set<String> keys = map.keySet();
            for(String key:keys){
                String value = map.get(key);
                /**
                 * 拿着key和value去es中匹配
                 * es中的列：
                 *   specs.机身颜色
                 *   specs.内存
                 *   specs.机身存储
                 * 所以我们需拼接
                 * specs: 是es中的map对象的名字
                 * key: map集合中的key
                 * .keyword:固定搭配
                 *
                 * 科普：springboot2.0.1-?  此处是需要加".keyword"
                 *      确认springboot2.1.1 此处是不需要加".keyword"
                 springboot2.2.2  此处是需要加".keyword"
                 *
                 */
                key = "specs." + key + ".keyword";
                // 添加条件
                boolQueryBuilder.must(QueryBuilders.termQuery(key,value));
            }
        }

        // 6 价格
        if(req.getMin_price()!=null){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(req.getMin_price()));
        }
        if(req.getMax_price()!=null){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(req.getMax_price()));
        }


        //7 排序
        //7.1 销量
        if("xl".equals(req.getSort_by())){
            queryBuilder.withSort(SortBuilders.fieldSort("seller_count").order(SortOrder.DESC));
        }
        //7.2 评论
        else if("pl".equals(req.getSort_by())){
            queryBuilder.withSort(SortBuilders.fieldSort("comment_count").order(SortOrder.DESC));
        }
        //7.3 上架时间
        else if("sj".equals(req.getSort_by())){
            queryBuilder.withSort(SortBuilders.fieldSort("on_sale_time").order(SortOrder.DESC));
        }
        //7.4 价格
        else if("jg".equals(req.getSort_by())&&"desc".equals(req.getSort_way())){
            queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
        }else if("jg".equals(req.getSort_by())&&"asc".equals(req.getSort_way())){
            queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
        }


        //8. 分页
        int pageNo = req.getPage() -1 ;//为什么要减1，因为elasticsearch的分页从0开始
        int size = req.getLimit();
        queryBuilder.withPageable(PageRequest.of(pageNo,size));

        //10 将booleanQuery关联到条件查询构建器
        queryBuilder.withQuery(boolQueryBuilder);
        //11 执行查询
        Page<SearchSku> page = skuRepository.search(queryBuilder.build());
        //12 获取总条数
        long totalElements = page.getTotalElements();
        //13 获取三级分类id
        Integer cat3id = req.getCatid();
        //14 封装 结果SkuResult
        List<SkuResult> list = new ArrayList<>();
        //14.1 遍历page，然后将结果封装到SkuResult中
        for(SearchSku ss:page){
            //14.2 创建SkuResult
            SkuResult skuResult = new SkuResult();
            skuResult.setId(ss.getId());
            skuResult.setGoods_name(ss.getSku_name());
            skuResult.setPrice(ss.getPrice());
            skuResult.setMidlogo(ss.getLogo());
            skuResult.setComment_count(ss.getComment_count());
            list.add(skuResult);
        }
        //15 封装SearchResult结果
        SearchResult sr = new SearchResult(0, "成功", list, (int)totalElements, cat3id);

        return sr;
    }

}
